package hsl.study.videocapturesystem.test;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class VideoCaptureSystem {
    private static final Logger LOGGER = Logger.getLogger(VideoCaptureSystem.class.getName());
    private final ExecutorService captureExecutor = Executors.newSingleThreadExecutor();
    private final ExecutorService saveExecutor = Executors.newSingleThreadExecutor();
    private final ExecutorService logExecutor = Executors.newSingleThreadExecutor();
    private final BlockingQueue<CapturedImage> imageQueue;
    private final String videoUrl;
    private final String outputDir;
    private final int fps;
    private String aiResultFile;
    public String get;
    private Process ffmpegProcess; // 保存FFmpeg进程引用，用于关闭

    public VideoCaptureSystem(String videoUrl, String outputDir, int fps, int queueCapacity) {
        this.videoUrl = videoUrl;
        this.outputDir = outputDir;
        this.fps = fps;
        this.imageQueue = new LinkedBlockingQueue<>(queueCapacity);
        initOutputDirectory();
    }

    private void initOutputDirectory() {
        try {
            Path dirPath = Paths.get(outputDir);
            if (!Files.exists(dirPath)) {
                Files.createDirectories(dirPath);
            }
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "初始化输出目录失败", e);
            throw new RuntimeException("初始化输出目录失败", e);
        }
    }

    public void start() {
        captureExecutor.submit(this::captureFrames);
        saveExecutor.submit(this::saveImages);
        logExecutor.submit(this::logStatus);
    }

    private void captureFrames() {
        try {
            // 构建FFmpeg命令：从视频流按指定帧率截取图像，通过管道输出PNG
            ProcessBuilder pb = new ProcessBuilder(
                    "ffmpeg",
                    "-hide_banner", // 隐藏FFmpeg版本信息
                    "-loglevel", "error", // 只输出错误信息
                    "-i", videoUrl, // 输入视频源
                    "-r", String.valueOf(fps), // 输出帧率
                    "-f", "image2pipe", // 输出格式为图像管道
                    "-vcodec", "png", // 编码为PNG
                    "-" // 输出到标准输出
            );
            pb.redirectErrorStream(false); // 错误流单独处理
            ffmpegProcess = pb.start();

            // 启动线程处理FFmpeg错误输出（关键：检测视频源是否有效）
            new Thread(() -> {
                try (BufferedReader errorReader = new BufferedReader(
                        new InputStreamReader(ffmpegProcess.getErrorStream()))) {
                    String errorLine;
                    while ((errorLine = errorReader.readLine()) != null) {
                        LOGGER.severe("FFmpeg错误: " + errorLine);
                        // 如果FFmpeg输出错误，中断当前截图线程
                        Thread.currentThread().interrupt();
                    }
                } catch (IOException e) {
                    LOGGER.log(Level.WARNING, "FFmpeg错误流读取失败", e);
                }
            }, "FFmpeg-Error-Handler").start();

            // 从FFmpeg的标准输出流读取图像数据（核心逻辑）
            try (InputStream in = ffmpegProcess.getInputStream()) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                // PNG图像以8字节签名开头：137 80 78 71 13 10 26 10
                byte[] pngSignature = {(byte) 137, 80, 78, 71, 13, 10, 26, 10};
                ByteArrayOutputStream imageBuffer = new ByteArrayOutputStream();
                boolean isCollecting = false;

                while (!Thread.currentThread().isInterrupted()
                        && (bytesRead = in.read(buffer)) != -1) {
                    for (int i = 0; i < bytesRead; i++) {
                        // 检测PNG签名开始位置
                        if (!isCollecting && i + 7 < bytesRead) {
                            boolean match = true;
                            for (int j = 0; j < 8; j++) {
                                if (buffer[i + j] != pngSignature[j]) {
                                    match = false;
                                    break;
                                }
                            }
                            if (match) {
                                // 找到新PNG的开始，重置缓冲区
                                imageBuffer.reset();
                                imageBuffer.write(buffer, i, bytesRead - i);
                                isCollecting = true;
                                break;
                            }
                        } else if (isCollecting) {
                            // 收集图像数据直到下一个签名或流结束
                            imageBuffer.write(buffer, i, 1);
                            // 简单检测：如果遇到PNG签名且缓冲区已有数据，说明当前图像结束
                            if (i + 7 < bytesRead) {
                                boolean nextSignature = true;
                                for (int j = 0; j < 8; j++) {
                                    if (buffer[i + j] != pngSignature[j]) {
                                        nextSignature = false;
                                        break;
                                    }
                                }
                                if (nextSignature) {
                                    // 当前图像数据收集完成
                                    byte[] imageData = imageBuffer.toByteArray();
                                    String imageName = Instant.now().toEpochMilli() + ".png";
                                    // 尝试添加到队列，队列满则执行拒绝策略（丢弃）
                                    if (!imageQueue.offer(new CapturedImage(imageName, imageData),
                                            1, TimeUnit.SECONDS)) {
                                        LOGGER.warning("队列已满，丢弃帧: " + imageName);
                                    }
                                    // 开始收集下一张图像
                                    imageBuffer.reset();
                                    imageBuffer.write(buffer, i, bytesRead - i);
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            // 等待FFmpeg进程结束
            int exitCode = ffmpegProcess.waitFor();
            LOGGER.info("FFmpeg进程结束，退出码: " + exitCode);

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            LOGGER.info("截图线程被中断");
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "截图过程IO错误", e);
        } finally {
            // 确保FFmpeg进程被销毁
            if (ffmpegProcess != null && ffmpegProcess.isAlive()) {
                ffmpegProcess.destroyForcibly();
            }
        }
    }

    private void saveImages() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                // 从队列取图像（阻塞直到有数据）
                CapturedImage image = imageQueue.take();
                Path filePath = Paths.get(outputDir, image.getName());
                Files.write(filePath, image.getData());
                LOGGER.info("保存图像成功: " + filePath);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            LOGGER.info("保存线程被中断");
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "图像保存失败", e);
        }
    }

    private void logStatus() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                LOGGER.info("队列状态: " + imageQueue.size() + "/" + imageQueue.remainingCapacity());
                Thread.sleep(5000); // 每5秒打印一次状态
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            LOGGER.info("日志线程被中断");
        }
    }

    public void shutdown() {
        // 中断所有线程
        captureExecutor.shutdownNow();
        saveExecutor.shutdownNow();
        logExecutor.shutdownNow();

        // 等待线程关闭
        try {
            if (!captureExecutor.awaitTermination(3, TimeUnit.SECONDS)) {
                LOGGER.warning("截图线程未能及时关闭");
            }
            if (!saveExecutor.awaitTermination(3, TimeUnit.SECONDS)) {
                LOGGER.warning("保存线程未能及时关闭");
            }
            if (!logExecutor.awaitTermination(3, TimeUnit.SECONDS)) {
                LOGGER.warning("日志线程未能及时关闭");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            LOGGER.warning("关闭过程被中断");
        }
    }

    public static void main(String[] args) {
        // 配置参数（请替换为你的实际视频源和输出路径）
        String videoUrl = "rtsp://admin:stmfnvr666@192.168.31.191/Streaming/Channels/501"; // 例如：RTSP摄像头流、本地视频文件路径
        String outputDir = "D:\\WORK\\output_frames"; // 输出目录（确保有写入权限）
        int fps = 2; // 每秒截取2帧
        int queueCapacity = 100; // 队列最大容量

        VideoCaptureSystem system = new VideoCaptureSystem(videoUrl, outputDir, fps, queueCapacity);
        system.start();

        // 示例：运行30秒后关闭（实际使用中可根据需求调整）
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            system.shutdown();
        }
    }

    // 图像数据封装类
    private static class CapturedImage {
        private final String name;
        private final byte[] data;

        public CapturedImage(String name, byte[] data) {
            this.name = name;
            this.data = data;
        }

        public String getName() {
            return name;
        }

        public byte[] getData() {
            return data;
        }
    }
}